﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Windows.Data;
using Microsoft.Forums.ForumsClient.Models;
using Microsoft.Forums.SyncService;
using Microsoft.Forums.ForumsProvider;
using Microsoft.Forums.OfflineStore;
using System.Diagnostics;
using Threading = System.Threading;
namespace Microsoft.Forums.ForumsClient.Controllers
{
    public class AppWindowController
    {
        readonly Window appWindow;

        /// <summary>
        ///  Get the application level data Model.
        /// </summary>
        public AppDataModel DataModel
        {
            get;
            private set;
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="AppWindowController"/> class.
        /// </summary>
        /// <param name="window">The window.</param>
        /// <param name="dataModel">The data model.</param>
        public AppWindowController(Window window, AppDataModel dataModel)
        {
            if (dataModel == null) throw new ArgumentNullException("dataModel", "dataModel cannot be null");

            appWindow = window;
            DataModel = dataModel;
            ApplyTheme(0);

        }

       

        /// <summary>
        /// Initializes the main window by populating data
        /// </summary>
        public void Initialize()
        {
            if (DatabaseUtilities.DoesDatabaseExist(DataModel.DatabaseConnectionString))
            {
                if (!DatabaseUtilities.DoesDatabaseMatchCurrentVersion(DataModel.DatabaseConnectionString))
                {
                    var result = MessageBox.Show(Properties.Resources.DBSchemaChangeMessage,
                                    Microsoft.Forums.ForumsClient.Properties.Resources.DBSchemaChangeTitle,
                                    MessageBoxButton.YesNo,
                                    MessageBoxImage.Exclamation);

                    if (result == MessageBoxResult.No)
                    {
                        Environment.Exit(0);
                    }

                    // Notify user that we need to create a new database
                    DatabaseUtilities.CreateNewDatabase(DataModel.DatabaseConnectionString);
                }
            }
            else
            {
                DatabaseUtilities.CreateNewDatabase(DataModel.DatabaseConnectionString);
            }

            // Populate forum list in background thread to have app startup be faster
            Threading.ThreadPool.QueueUserWorkItem
                (
                    delegate
                    {
                        DataModel.SubscribedForums.Refresh();
                    }
                );


            LoadApplicationSettings();
            
            if (LogOn())
            {
                using (var db = DataModel.ReadOnlyDataContext)
                {
                    if (db.Forums.Count() < 1)
                    {
                        ShowSubscribeDialog();
                    }
                }
            }

        }

        /// <summary>
        /// Loads the application settings.
        /// </summary>
        private void LoadApplicationSettings()
        {

            // If the DefaultSyncBatchSize value is greater than 0 then use that 
            // batch size to download from the server or else leave it with the 
            // default value set by the MicrosoftForumsServiceProvider constructor
            if (Properties.Settings.Default.DefaultSyncBatchSize > 0)
            {
                DataModel.ServiceProvider.BatchSize = Properties.Settings.Default.DefaultSyncBatchSize;
            }

            DataModel.CurrentUser.UserInfo = Properties.Settings.Default.UserInfo;
            DataModel.SynchronizationManager.SyncFrequency = Properties.Settings.Default.SyncFrequency;
            DataModel.SynchronizationManager.IsSchedulerEnabled = Properties.Settings.Default.IsAutoSyncOn;
            DataModel.SynchronizationManager.SchedulerSynchronizationLimit = Properties.Settings.Default.SynchronizationLimit;
        }

        /// <summary>
        ///  ApplyTheme to your app
        /// </summary>
        /// <param name="themeIndex">Index into your themes list</param>
        private void ApplyTheme(int themeIndex)
        {
            // Note that this would override any existing resources you have
            // specified in Application.Resources section of you App.xaml
            // If you add entries there then you should merge this 

            var resourceDict = ((App)Application.Current).Themes.ElementAt(DataModel.ThemeIndex).Value;
            Application.Current.Resources.MergedDictionaries.Remove(resourceDict);
            Application.Current.Resources.MergedDictionaries.Add(((App)Application.Current).Themes.ElementAt(themeIndex).Value);
        }

        #region ChangeTheme

        internal bool CanChangeTheme
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Change the current theme
        /// </summary>
        internal void ChangeTheme()
        {
            //Cycle through the list of themes
            ++DataModel.ThemeIndex;

            if (DataModel.ThemeIndex >= ((App)App.Current).Themes.Count)
                DataModel.ThemeIndex = 0;

            // Apply the current theme
            ApplyTheme(DataModel.ThemeIndex);
        }
        #endregion

        #region UnsubscribeForum

        internal bool CanUnsubscribeForum
        {
            get
            {
                var forumFolderModel = DataModel.SelectedFolder as ForumFolderViewModel;
                return (forumFolderModel != null && !forumFolderModel.IsSyncInProgress);
            }
        }

        /// <summary>
        /// Unsubscribed the selected forum
        /// </summary>
        internal void UnsubscribeForum()
        {
            var selected = DataModel.SelectedFolder as ForumFolderViewModel;
            if (selected == null)
            {
                // Not a forum folder view object
                return;
            }

            try
            {
                DataModel.SynchronizationManager.Controller.UnsubscribeFromForum(selected.Forum.Id);
                selected.IsSyncInProgress = true;
                DataModel.SubscribedForums.Remove(selected);
                DataModel.SynchronizationManager.RemoveForumFromScheduler(selected);
            }
            catch (SynchronizationDatabaseException)
            {
                // TODO: Notify user that we can't find the forum in the database
            }
            catch (SynchronizationInProgressException)
            {
                // Notify user than we can't unsubscribe since a synchronization of that forum is in progress
                MessageBox.Show(Properties.Resources.SyncInProgressContent + Environment.NewLine + selected.Forum.DisplayName + "." + Properties.Resources.TryagainLaterContent,
                        Properties.Resources.UnableToUnsubscribeContent, MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        #endregion

        #region SynchronizeAllForums

        /// <summary>
        /// Gets a value indicating whether we can synchronize all forums.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can synchronize all forums; otherwise, <c>false</c>.
        /// </value>
        internal bool CanSynchronizeAllForums
        {
            get
            {
                return DataModel.SubscribedForums.Count > 0;
            }
        }

        /// <summary>
        /// Synchronize all the subscribed forums
        /// </summary>
        internal void SynchronizeAllForums()
        {
            LogOn();

            if (DataModel.CurrentUser.LogOnState == LogOnStatus.Authenticated)
            {
                foreach (var forum in DataModel.SubscribedForums)
                {
                    if (!forum.IsSyncInProgress)
                    {
                        forum.IsSyncInProgress = true;
                        Threading.ThreadPool.QueueUserWorkItem(delegate
                        {
                            try
                            {
                                DataModel.SynchronizationManager.Controller.SynchronizeForumAsync(forum.Forum.Id);
                            }
                            catch (SynchronizationDatabaseException)
                            {
                            }
                            catch (SynchronizationInProgressException)
                            {
                            }
                        });
                    }
                }
            }
        }

        #endregion

        #region SynchronizeForum

        /// <summary>
        /// Gets a value indicating whether we can synchronize the selected forum.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can synchronize forum; otherwise, <c>false</c>.
        /// </value>
        internal bool CanSynchronizeForum
        {
            get
            {
                var forumFolderModel = DataModel.SelectedFolder as ForumFolderViewModel;
                return (forumFolderModel != null && !forumFolderModel.IsSyncInProgress);
            }
        }

        /// <summary>
        /// Synchronize the selected forum
        /// </summary>
        internal void SynchronizeForum()
        {
            
            var selected = DataModel.SelectedFolder as ForumFolderViewModel;
            if (selected == null)
            {
                // Not a forum folder view object
                return;
            }

            LogOn();

            if (DataModel.CurrentUser.LogOnState == LogOnStatus.Authenticated)
            {
                selected.IsSyncInProgress = true;
                Threading.ThreadPool.QueueUserWorkItem(delegate
                {
                    try
                    {
                        DataModel.SynchronizationManager.Controller.SynchronizeForumAsync(selected.Forum.Id);
                    }
                    catch (SynchronizationDatabaseException)
                    {
                        // TODO: Notify user that we can't find the forum in the database
                    }
                    catch (SynchronizationInProgressException)
                    {
                        MessageBox.Show(Properties.Resources.SyncInProgressContent + Environment.NewLine + selected.Forum.DisplayName + "." + Properties.Resources.TryagainLaterContent,
                            Properties.Resources.UnableToSynchronizeContent, MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                });
            }
        }

        #endregion

        #region Subscribe Dialog

        internal bool CanShowSubscribeDialog
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///  On User clicking Subscribe Button on the menu bar.
        /// </summary>
        internal void ShowSubscribeDialog()
        {
            LogOn();

            if (DataModel.CurrentUser.LogOnState == LogOnStatus.Authenticated)
            {
                SubscribeToForumsDataModel subscribeModel = new SubscribeToForumsDataModel();
                SubscribeToForumsDialog subscriptionDlg = new SubscribeToForumsDialog(subscribeModel);
                subscriptionDlg.Owner = appWindow;
                subscriptionDlg.ShowDialog();
                if (subscriptionDlg.DialogResult == true)
                {
                    DataModel.SubscribedForums.Refresh();
                }
            }
        }
        #endregion

        #region Logon


        /// <summary>
        /// Gets a value indicating whether the user can log on.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can log on; otherwise, <c>false</c>.
        /// </value>
        internal bool CanLogOn
        {
            get
            {
                return DataModel.CurrentUser.LogOnState == LogOnStatus.Offline;
            }
        }

        /// <summary>
        /// Try to logon to the web service
        /// </summary>
        internal bool LogOn()
        {
            if (DataModel.Network.IsConnected == false)
            {
                // Consider to replace this later by updating the Status Bar Message.
                MessageBox.Show(Properties.Resources.NotConnectedToInternetContent,
                    Properties.Resources.NotConnectedContent,
                    MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);
                return false;
            }

            // If I am already logged in return. We need to revisit this later.
            // Currently the ticket is not getting invalidated if we remain disconnected
            // for a while and then try to reconnect with the same ticket later.
            if (DataModel.CurrentUser.LogOnState != LogOnStatus.Offline)
            {
                return true;
            }

            var authInfo = new AuthenticationInformation();
            if (DataModel.ServiceProvider.TryAuthenticate(ref authInfo))
            {
                var userName = authInfo.UserName;
                DataModel.CurrentUser.AuthenticationTicket = authInfo.Ticket;
                DataModel.CurrentUser.LogOnName = userName;
                DataModel.CurrentUser.LogOnState = LogOnStatus.Authenticated;
                DataModel.ServiceProvider.AuthenticationTicket = DataModel.CurrentUser.AuthenticationTicket;
                DataModel.CurrentUser.UserInfo = DataModel.ServiceProvider.CurrentUser;
                Properties.Settings.Default.UserInfo = DataModel.CurrentUser.UserInfo;
                return true;
            }
            else
            {
                DataModel.CurrentUser.LogOnState = LogOnStatus.Offline;
                return false;
            }

            
        }
        #endregion

        #region Options Dialog

        /// <summary>
        /// CanExecute delegate - Returns true
        /// </summary>
        internal bool CanShowOptionsDialog
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///  User clicked the Synch Settings Button.
        /// </summary>
        internal void ShowOptionsDialog()
        {
            OptionsDataModel settingsModel = new OptionsDataModel();
            OptionsDialog settingsDlg = new OptionsDialog(settingsModel);
            settingsDlg.Owner = appWindow;
            settingsDlg.ShowDialog();

            if (settingsDlg.DialogResult == true)
            {
                LoadApplicationSettings();
            }
        }
        #endregion


        #region ShowCreateThreadForm
        /// <summary>
        /// Gets a value indicating whether this instance can show create reply form.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can show create reply form; otherwise, <c>false</c>.
        /// </value>
        internal bool CanShowCreateThreadForm
        {
            get
            {
                return ((DataModel.SelectedFolder as ForumFolderViewModel) != null);
            }
        }

        /// <summary>
        /// Shows the create thread form.
        /// </summary>
        internal void ShowCreateThreadForm()
        {

        }
        #endregion
    }
}
